/*     */ package com.zimbra.cs.db;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.stats.StopWatch;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.SystemUtil;
/*     */ import com.zimbra.common.util.ValueCounter;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import java.sql.Connection;
/*     */ import java.sql.DriverManager;
/*     */ import java.sql.PreparedStatement;
/*     */ import java.sql.ResultSet;
/*     */ import java.sql.SQLException;
/*     */ import java.sql.Statement;
/*     */ import java.util.Iterator;
/*     */ import java.util.Properties;
/*     */ import org.apache.commons.dbcp.ConnectionFactory;
/*     */ import org.apache.commons.dbcp.PoolableConnectionFactory;
/*     */ import org.apache.commons.dbcp.PoolingDataSource;
/*     */ import org.apache.commons.pool.impl.GenericObjectPool;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class DbPool
/*     */ {
/*     */   private static PoolingDataSource sPoolingDataSource;
/*     */   private static String sRootUrl;
/*     */   private static String sLoggerRootUrl;
/*     */   private static GenericObjectPool sConnectionPool;
/*     */   private static boolean sIsInitialized;
/*     */   private static boolean isShutdown;
/*  54 */   private static boolean isUsageWarningEnabled = true;
/*     */   
/*  56 */   static ValueCounter<String> sConnectionStackCounter = new ValueCounter();
/*     */   
/*     */   public static class DbConnection {
/*     */     private final Connection connection;
/*     */     private Throwable mStackTrace;
/*     */     Integer mboxId;
/*     */     
/*     */     DbConnection(Connection conn) {
/*  64 */       this.connection = conn;
/*     */     }
/*     */     
/*     */     DbConnection(Connection conn, Integer mboxId) {
/*  68 */       this(conn);
/*  69 */       this.mboxId = mboxId;
/*     */     }
/*     */     
/*     */     public Connection getConnection() {
/*  73 */       return this.connection;
/*     */     }
/*     */     
/*     */     public void setTransactionIsolation(int level) throws ServiceException {
/*     */       try {
/*  78 */         this.connection.setTransactionIsolation(level);
/*     */       } catch (SQLException e) {
/*  80 */         throw ServiceException.FAILURE("setting database connection isolation level", e);
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */     public void disableForeignKeyConstraints()
/*     */       throws ServiceException
/*     */     {
/*  89 */       PreparedStatement stmt = null;
/*     */       try {
/*  91 */         String sql = "SET FOREIGN_KEY_CHECKS=0";
/*  92 */         stmt = new StatTrackingPreparedStatement(this.connection.prepareStatement(sql), sql);
/*  93 */         stmt.execute();
/*     */       } catch (SQLException e) {
/*  95 */         throw ServiceException.FAILURE("disabling foreign key constraints", e);
/*     */       } finally {
/*  97 */         DbPool.closeStatement(stmt);
/*     */       }
/*     */     }
/*     */     
/*     */     public void enableForeignKeyConstraints() throws ServiceException {
/* 102 */       String sql = "SET FOREIGN_KEY_CHECKS=1";
/* 103 */       PreparedStatement stmt = null;
/*     */       try {
/* 105 */         stmt = new StatTrackingPreparedStatement(this.connection.prepareStatement(sql), sql);
/* 106 */         stmt.execute();
/*     */       } catch (SQLException e) {
/* 108 */         throw ServiceException.FAILURE("disabling foreign key constraints", e);
/*     */       } finally {
/* 110 */         DbPool.closeStatement(stmt);
/*     */       }
/*     */     }
/*     */     
/*     */     public PreparedStatement prepareStatement(String sql) throws SQLException {
/* 115 */       return new StatTrackingPreparedStatement(this.connection.prepareStatement(sql), sql);
/*     */     }
/*     */     
/*     */     public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
/* 119 */       return new StatTrackingPreparedStatement(this.connection.prepareStatement(sql, autoGeneratedKeys), sql);
/*     */     }
/*     */     
/*     */     public void rollback() throws ServiceException {
/*     */       try {
/* 124 */         this.connection.rollback();
/*     */       } catch (SQLException e) {
/* 126 */         throw ServiceException.FAILURE("rolling back database transaction", e);
/*     */       }
/*     */     }
/*     */     
/*     */     public void commit() throws ServiceException {
/*     */       try {
/* 132 */         this.connection.commit();
/*     */       } catch (SQLException e) {
/* 134 */         throw ServiceException.FAILURE("committing database transaction", e);
/*     */       }
/*     */     }
/*     */     
/*     */     public void close() throws ServiceException
/*     */     {
/*     */       try {
/* 141 */         Db.getInstance().preClose(this);
/*     */       } catch (SQLException e) {
/* 143 */         ZimbraLog.sqltrace.warn("DB connection pre-close processing caught exception", e);
/*     */       }
/*     */       
/*     */       try
/*     */       {
/* 148 */         this.connection.close();
/*     */       } catch (SQLException e) { String stackTrace;
/* 150 */         throw ServiceException.FAILURE("closing database connection", e);
/*     */ 
/*     */ 
/*     */       }
/*     */       finally
/*     */       {
/*     */ 
/* 157 */         if ((this.mStackTrace != null) && (ZimbraLog.dbconn.isDebugEnabled())) {
/* 158 */           String stackTrace = SystemUtil.getStackTrace(this.mStackTrace);
/* 159 */           synchronized (DbPool.sConnectionStackCounter) {
/* 160 */             DbPool.sConnectionStackCounter.decrement(stackTrace);
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     
/*     */     void setStackTrace(Throwable t)
/*     */     {
/* 168 */       this.mStackTrace = t;
/*     */     }
/*     */     
/*     */     public void closeQuietly() {
/*     */       try {
/* 173 */         if (!this.connection.isClosed()) {
/* 174 */           close();
/*     */         }
/*     */       } catch (ServiceException e) {
/* 177 */         ZimbraLog.sqltrace.warn("ServiceException ignored", e);
/*     */       } catch (SQLException e) {
/* 179 */         ZimbraLog.sqltrace.warn("SQLException ignored", e);
/*     */       }
/*     */     }
/*     */     
/*     */     public void closeQuietly(Statement stmt) {
/* 184 */       if (stmt == null) {
/* 185 */         return;
/*     */       }
/*     */       try {
/* 188 */         stmt.close();
/*     */       } catch (SQLException e) {
/* 190 */         ZimbraLog.sqltrace.warn("SQL error ignored", e);
/*     */       }
/*     */     }
/*     */     
/*     */     public void closeQuietly(ResultSet rs) {
/* 195 */       if (rs == null) {
/* 196 */         return;
/*     */       }
/*     */       try {
/* 199 */         rs.close();
/*     */       } catch (SQLException e) {
/* 201 */         ZimbraLog.sqltrace.warn("SQL error ignored", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   static abstract class PoolConfig {
/*     */     String mDriverClassName;
/*     */     int mPoolSize;
/*     */     String mRootUrl;
/*     */     String mConnectionUrl;
/*     */     String mLoggerUrl;
/*     */     boolean mSupportsStatsCallback;
/*     */     Properties mDatabaseProperties;
/* 214 */     byte whenExhaustedAction = 1;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static synchronized void startup()
/*     */   {
/* 222 */     if (isInitialized()) {
/* 223 */       return;
/*     */     }
/* 225 */     PoolConfig pconfig = Db.getInstance().getPoolConfig();
/*     */     
/* 227 */     String drivers = System.getProperty("jdbc.drivers");
/* 228 */     if (drivers == null) {
/* 229 */       System.setProperty("jdbc.drivers", pconfig.mDriverClassName);
/*     */     }
/* 231 */     sRootUrl = pconfig.mRootUrl;
/* 232 */     sLoggerRootUrl = pconfig.mLoggerUrl;
/* 233 */     sIsInitialized = true;
/* 234 */     waitForDatabase();
/*     */   }
/*     */   
/*     */   private static void waitForDatabase() {
/* 238 */     DbConnection conn = null;
/* 239 */     int RETRY_SECONDS = 5;
/*     */     
/* 241 */     while (conn == null) {
/*     */       try {
/* 243 */         conn = getConnection();
/*     */       } catch (ServiceException e) {
/* 245 */         ZimbraLog.misc.warn("Could not establish a connection to the database.  Retrying in %d seconds.", Integer.valueOf(5), e);
/*     */         try
/*     */         {
/* 248 */           Thread.sleep(5000L);
/*     */         }
/*     */         catch (InterruptedException e2) {}
/*     */       }
/*     */     }
/*     */     
/* 254 */     quietClose(conn);
/*     */   }
/*     */   
/*     */   private static boolean isInitialized() {
/* 258 */     return sIsInitialized;
/*     */   }
/*     */   
/*     */ 
/*     */   public static void loadSettings()
/*     */   {
/*     */     try
/*     */     {
/* 266 */       long slowThreshold = Provisioning.getInstance().getLocalServer().getDatabaseSlowSqlThreshold();
/* 267 */       DebugPreparedStatement.setSlowSqlThreshold(slowThreshold);
/*     */     } catch (ServiceException e) {
/* 269 */       ZimbraLog.system.warn("Unable to set slow SQL threshold.", e);
/*     */     }
/*     */   }
/*     */   
/*     */   private static synchronized PoolingDataSource getPool()
/*     */   {
/* 275 */     if (isShutdown) {
/* 276 */       throw new RuntimeException("DbPool permanently shutdown");
/*     */     }
/* 278 */     if (sPoolingDataSource != null) {
/* 279 */       return sPoolingDataSource;
/*     */     }
/* 281 */     PoolConfig pconfig = Db.getInstance().getPoolConfig();
/* 282 */     sConnectionPool = new GenericObjectPool(null, pconfig.mPoolSize, pconfig.whenExhaustedAction, -1L, pconfig.mPoolSize);
/* 283 */     ConnectionFactory cfac = ZimbraConnectionFactory.getConnectionFactory(pconfig);
/*     */     
/* 285 */     boolean defAutoCommit = false;boolean defReadOnly = false;
/* 286 */     new PoolableConnectionFactory(cfac, sConnectionPool, null, null, defReadOnly, defAutoCommit);
/*     */     try
/*     */     {
/* 289 */       Class.forName(pconfig.mDriverClassName).newInstance();
/* 290 */       Class.forName("org.apache.commons.dbcp.PoolingDriver");
/*     */     } catch (Exception e) {
/* 292 */       ZimbraLog.system.fatal("can't instantiate DB driver/pool class", e);
/* 293 */       System.exit(1);
/*     */     }
/*     */     try
/*     */     {
/* 297 */       PoolingDataSource pds = new PoolingDataSource(sConnectionPool);
/* 298 */       pds.setAccessToUnderlyingConnectionAllowed(true);
/*     */       
/* 300 */       Db.getInstance().startup(pds, pconfig.mPoolSize);
/*     */       
/* 302 */       sPoolingDataSource = pds;
/*     */     } catch (SQLException e) {
/* 304 */       ZimbraLog.system.fatal("can't initialize connection pool", e);
/* 305 */       System.exit(1);
/*     */     }
/*     */     
/* 308 */     if (pconfig.mSupportsStatsCallback) {
/* 309 */       ZimbraPerf.addStatsCallback(new DbStats());
/*     */     }
/* 311 */     return sPoolingDataSource;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static DbConnection getConnection()
/*     */     throws ServiceException
/*     */   {
/* 322 */     return getConnection(null);
/*     */   }
/*     */   
/*     */   public static DbConnection getConnection(Mailbox mbox) throws ServiceException {
/* 326 */     if (!isInitialized()) {
/* 327 */       throw ServiceException.FAILURE("Database connection pool not initialized.", null);
/*     */     }
/* 329 */     Integer mboxId = Integer.valueOf(mbox != null ? mbox.getId() : -1);
/*     */     try {
/* 331 */       Db.getInstance().preOpen(mboxId);
/* 332 */       long start = ZimbraPerf.STOPWATCH_DB_CONN.start();
/*     */       
/*     */ 
/* 335 */       PoolingDataSource pool = getPool();
/* 336 */       checkPoolUsage();
/*     */       
/* 338 */       Connection dbconn = null;
/* 339 */       DbConnection conn = null;
/*     */       try {
/* 341 */         dbconn = pool.getConnection();
/*     */         
/* 343 */         if (dbconn.getAutoCommit()) {
/* 344 */           dbconn.setAutoCommit(false);
/*     */         }
/*     */         
/*     */ 
/* 348 */         if (Db.supports(Db.Capability.READ_COMMITTED_ISOLATION)) {
/* 349 */           dbconn.setTransactionIsolation(2);
/*     */         }
/* 351 */         conn = new DbConnection(dbconn, mboxId);
/* 352 */         Db.getInstance().postOpen(conn);
/*     */       } catch (SQLException e) {
/*     */         try {
/* 355 */           if ((dbconn != null) && (!dbconn.isClosed()))
/* 356 */             dbconn.close();
/*     */         } catch (SQLException e2) {
/* 358 */           ZimbraLog.sqltrace.warn("DB connection close caught exception", e);
/*     */         }
/* 360 */         throw ServiceException.FAILURE("getting database connection", e);
/*     */       }
/*     */       
/*     */ 
/* 364 */       if (ZimbraLog.dbconn.isDebugEnabled()) {
/* 365 */         Throwable t = new Throwable();
/* 366 */         conn.setStackTrace(t);
/*     */         
/* 368 */         String stackTrace = SystemUtil.getStackTrace(t);
/* 369 */         synchronized (sConnectionStackCounter) {
/* 370 */           sConnectionStackCounter.increment(stackTrace);
/*     */         }
/*     */       }
/* 373 */       if (mbox != null) {
/* 374 */         Db.registerDatabaseInterest(conn, mbox);
/*     */       }
/* 376 */       ZimbraPerf.STOPWATCH_DB_CONN.stop(start);
/* 377 */       return conn;
/*     */     }
/*     */     catch (ServiceException se) {
/* 380 */       Db.getInstance().abortOpen(mboxId);
/* 381 */       throw se;
/*     */     }
/*     */   }
/*     */   
/*     */   private static void checkPoolUsage() {
/* 386 */     int numActive = sConnectionPool.getNumActive();
/* 387 */     int maxActive = sConnectionPool.getMaxActive();
/*     */     
/* 389 */     if (numActive <= maxActive * 0.75D) {
/* 390 */       return;
/*     */     }
/* 392 */     String stackTraceMsg = "Turn on debug logging for zimbra.dbconn to see stack traces of connections not returned to the pool.";
/* 393 */     if (ZimbraLog.dbconn.isDebugEnabled()) {
/* 394 */       StringBuilder buf = new StringBuilder();
/* 395 */       synchronized (sConnectionStackCounter) {
/* 396 */         Iterator<String> i = sConnectionStackCounter.iterator();
/* 397 */         while (i.hasNext()) {
/* 398 */           String stackTrace = (String)i.next();
/* 399 */           int count = sConnectionStackCounter.getCount(stackTrace);
/* 400 */           if (count == 0) {
/* 401 */             i.remove();
/*     */           } else {
/* 403 */             buf.append(count + " connections allocated at " + stackTrace + "\n");
/*     */           }
/*     */         }
/*     */       }
/* 407 */       stackTraceMsg = buf.toString();
/*     */     }
/* 409 */     String logMsg = "Connection pool is 75%% utilized (%d connections out of a maximum of %d in use).  %s";
/* 410 */     if (isUsageWarningEnabled) {
/* 411 */       ZimbraLog.dbconn.warn(logMsg, new Object[] { Integer.valueOf(numActive), Integer.valueOf(maxActive), stackTraceMsg });
/*     */     } else {
/* 413 */       ZimbraLog.dbconn.debug(logMsg, new Object[] { Integer.valueOf(numActive), Integer.valueOf(maxActive), stackTraceMsg });
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static DbConnection getMaintenanceConnection()
/*     */     throws ServiceException
/*     */   {
/*     */     try
/*     */     {
/* 425 */       String user = LC.zimbra_mysql_user.value();
/* 426 */       String pwd = LC.zimbra_mysql_password.value();
/* 427 */       Connection conn = DriverManager.getConnection(sRootUrl + "?user=" + user + "&password=" + pwd);
/* 428 */       conn.setAutoCommit(false);
/* 429 */       return new DbConnection(conn);
/*     */     } catch (SQLException e) {
/* 431 */       throw ServiceException.FAILURE("getting database maintenance connection", e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static DbConnection getLoggerConnection()
/*     */     throws ServiceException
/*     */   {
/*     */     try
/*     */     {
/* 443 */       String user = LC.zimbra_mysql_user.value();
/* 444 */       String pwd = null;
/* 445 */       Connection conn = DriverManager.getConnection(sLoggerRootUrl + "?user=" + user + "&password=" + pwd);
/* 446 */       return new DbConnection(conn);
/*     */     } catch (SQLException e) {
/* 448 */       throw ServiceException.FAILURE("getting database logger connection", e);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void quietClose(DbConnection conn)
/*     */   {
/* 457 */     if (conn != null) {
/*     */       try {
/* 459 */         if ((conn.getConnection() != null) && (!conn.getConnection().isClosed()))
/* 460 */           conn.close();
/*     */       } catch (SQLException e) {
/* 462 */         ZimbraLog.sqltrace.warn("quietClose caught exception", e);
/*     */       } catch (ServiceException e) {
/* 464 */         ZimbraLog.sqltrace.warn("quietClose caught exception", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void quietRollback(DbConnection conn)
/*     */   {
/* 474 */     if (conn != null) {
/*     */       try {
/* 476 */         if ((conn.getConnection() != null) && (!conn.getConnection().isClosed()))
/* 477 */           conn.rollback();
/*     */       } catch (SQLException e) {
/* 479 */         ZimbraLog.sqltrace.warn("quietRollback caught exception", e);
/*     */       } catch (ServiceException e) {
/* 481 */         ZimbraLog.sqltrace.warn("quietRollback caught exception", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void closeStatement(Statement stmt)
/*     */     throws ServiceException
/*     */   {
/* 492 */     if (stmt != null) {
/*     */       try {
/* 494 */         stmt.close();
/*     */       } catch (SQLException e) {
/* 496 */         throw ServiceException.FAILURE("closing statement", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public static void quietCloseStatement(Statement stmt) {
/*     */     try {
/* 503 */       if (stmt != null) {
/* 504 */         stmt.close();
/*     */       }
/*     */     }
/*     */     catch (SQLException e) {}
/*     */   }
/*     */   
/*     */ 
/*     */   public static void closeResults(ResultSet rs)
/*     */     throws ServiceException
/*     */   {
/* 514 */     if (rs != null) {
/*     */       try {
/* 516 */         rs.close();
/*     */       } catch (SQLException e) {
/* 518 */         throw ServiceException.FAILURE("closing statement", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public static int getSize()
/*     */   {
/* 527 */     return sConnectionPool.getNumActive();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   static synchronized void close()
/*     */     throws Exception
/*     */   {
/* 537 */     if (sConnectionPool != null) {
/* 538 */       sConnectionPool.close();
/* 539 */       sConnectionPool = null;
/*     */     }
/* 541 */     sPoolingDataSource = null;
/* 542 */     Db.getInstance().shutdown();
/*     */   }
/*     */   
/*     */   public static synchronized void shutdown() throws Exception {
/* 546 */     isShutdown = true;
/* 547 */     close();
/*     */   }
/*     */   
/*     */   public static void disableUsageWarning() {
/* 551 */     isUsageWarningEnabled = false;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/db/DbPool.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */